/*
 * UserNet  --  TCP/IP implementation in userspace
 * Copyright (C) 2010  Alex Diban
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <stdio.h>
#include "unet/ip.h"
#include <stdlib.h>
#include <string.h>


/* This function is called every time an incoming packet is received by
   the client.  Since it comes from the server, it is garanteed that we're
   its destination address.  Depending on the packet type, it should be
   passed to tcp.c, to udp.c or dropped.  */

void
unet_ip_incoming_packet (const uint8_t *packet, const uint32_t len)
{
  debug_printf("ip","IP: incoming %u-byte packet\n", len);
  
  struct unet_ip_packet * packet_ip;
  packet_ip=(struct unet_ip_packet*) packet;
  
  struct in_addr saddr;
  struct in_addr daddr;
    
  saddr.s_addr=packet_ip->header.saddr;
  daddr.s_addr=packet_ip->header.daddr;
  
  //Envio el segmento (packet_ip->payload) a quien corresponda 
  
  if (packet_ip->header.protocol==0x06) //Para TCP
  {
    debug_printf("ip","IP: This packet is for TCP\n");
    unet_tcp_deliver(saddr, daddr, packet_ip->payload, packet_ip->header.tot_len);
  }
  else if (packet_ip->header.protocol==0x11) //Para UDP
  {
    debug_printf("ip","IP: This packet is for UDP\n");
    unet_udp_incoming(daddr, packet_ip->payload, packet_ip->header.tot_len);
  }
  
}

/* Esta funcion recibe un paquete de una capa superior, la encapsula como paquete IP y la manda al servidor */
int 
unet_transport_send_packet(enum ip_protocols type,struct in_addr ip_addr,void * buff,size_t len)
{

  debug_printf("ip","IP: received segment of %ul bytes from tcp/udp \n", (unsigned int)len);
    
  struct unet_ip_packet * packet_ip;
  uint32_t ip_len =sizeof(packet_ip->header)+len;
  packet_ip= malloc (ip_len);

  //Damos valores a los campos de la cabecera ip
  packet_ip->header.version=0x04;
  packet_ip->header.ihl=IP_HEADER_SIZE;

  packet_ip->header.tos=0;
  packet_ip->header.tot_len=htons(ip_len);
  
  packet_ip->header.id=0;	//TODO
  packet_ip->header.frag_off=0;	//TODO: Fragmentacion
  
  //Valor por defecto
   packet_ip->header.ttl=64;	

  if (type==UNET_TCP) packet_ip->header.protocol=0x06;
  else if (type==UNET_UDP) packet_ip->header.protocol=0x11;

  //se asigna en modulo ip de servidor
  packet_ip->header.saddr=0;
  //addr de destino
  packet_ip->header.daddr=ip_addr.s_addr;	
  //se calcula en el servidor, una vez asignada la saddr
  packet_ip->header.check=0; 	

  //Copia el segmento TCP/UDP en el payload de IP
  memcpy(packet_ip->payload,buff,len);

  //Envia el paquete IP al servidor
  unet_rpc_ip_send_packet((const uint8_t*)packet_ip, ip_len);
  
  //Retornamos 1: Metodo funcional  
  return 1;
}
